@file:Suppress("DEPRECATION")

package chooongg.base.utils

import android.Manifest
import android.net.ConnectivityManager
import android.os.Build
import android.telephony.TelephonyManager
import android.util.Log
import androidx.annotation.RequiresPermission
import chooongg.base.Utils
import java.net.InetAddress
import java.net.NetworkInterface
import java.net.SocketException
import java.net.UnknownHostException
import java.util.*

private const val NETWORK_TYPE_GSM = 16
private const val NETWORK_TYPE_TD_SCDMA = 17
private const val NETWORK_TYPE_IWLAN = 18

enum class NetworkType {
    NETWORK_WIFI,
    NETWORK_4G,
    NETWORK_3G,
    NETWORK_2G,
    NETWORK_UNKNOWN,
    NETWORK_NO
}

/**
 * 判断是否有网络连接
 */
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun networkIsConnected(): Boolean {
    val info = getActiveNetworkInfo()
    return info != null && info.isConnected
}

/**
 * 使用ping判断是否有网络连接
 *
 * @param ip IP地址
 */
@RequiresPermission(Manifest.permission.INTERNET)
fun networkIsAvailableByPing(ip: String? = null): Boolean {
    var ipCopy = ip
    if (ipCopy == null || ipCopy.isEmpty()) ipCopy = "223.5.5.5"// 默认IP地址ping
    val result = ShellUtils.execCmd(String.format("ping -c 1 %s", ipCopy), false)
    if (result.errorMsg != null) Log.d("*NETWORK*", "ping errorMsg:" + result.errorMsg)
    if (result.successMsg != null) Log.d("*NETWORK*", "ping successMsg:" + result.successMsg)
    return result.result == 0
}

/**
 * 判断移动数据是否打开
 */
fun networkGetMobileDataEnabled(): Boolean {
    val manager = Utils.app.getTelephonyManager()
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) manager.isDataEnabled
    else try {
        val getMobileDataEnabledMethod = manager.javaClass.getDeclaredMethod("getDataEnabled")
        getMobileDataEnabledMethod.invoke(manager) as Boolean
    } catch (e: Exception) {
        false
    }
}

/**
 * 打开或关闭移动数据
 *
 * @param enabled 是否启用
 */
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
fun networkSetMobileDataEnabled(enabled: Boolean) {
    val manager = Utils.app.getTelephonyManager()
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) manager.isDataEnabled = enabled
    else try {
        val setMobileDataEnabledMethod =
            manager.javaClass.getDeclaredMethod("setDataEnabled", Boolean::class.javaPrimitiveType)
        setMobileDataEnabledMethod.invoke(manager, enabled)
    } catch (e: Exception) {
    }
}

/**
 * 判断网络是否是移动数据
 */
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun networkIsMobileData(): Boolean {
    val info = getActiveNetworkInfo()
    return (null != info && info.isAvailable && info.type == ConnectivityManager.TYPE_MOBILE)
}

/**
 * 判断网络是否是 4G
 */
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun networkIs4G(): Boolean {
    val info = getActiveNetworkInfo()
    return (info != null && info.isAvailable && info.subtype == TelephonyManager.NETWORK_TYPE_LTE)
}

/**
 * 判断 wifi 是否打开
 */
@RequiresPermission(Manifest.permission.ACCESS_WIFI_STATE)
fun networkGetWifiEnabled() = Utils.app.getWifiManager().isWifiEnabled

/**
 * 打开或关闭 wifi
 *
 * @param enabled 是否开启
 */
@RequiresPermission(Manifest.permission.CHANGE_WIFI_STATE)
fun networkSetWifiEnabled(enabled: Boolean) {
    val manager = Utils.app.getWifiManager()
    if (enabled) if (!manager.isWifiEnabled) manager.isWifiEnabled = true
    else if (manager.isWifiEnabled) manager.isWifiEnabled = false
}

/**
 * 判断 wifi 是否连接状态
 */
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun networkIsWifiConnected(): Boolean {
    val manager = Utils.app.getConnectivityManager()
    return (manager.activeNetworkInfo != null && manager.activeNetworkInfo?.type == ConnectivityManager.TYPE_WIFI)
}

/**
 * 判断 wifi 数据是否可用
 */
@RequiresPermission(allOf = [Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.INTERNET])
fun networkIsWifiAvailable() = networkGetWifiEnabled() && networkIsAvailableByPing()


/**
 * 获取移动网络运营商名称
 */
fun networkGetNetworkOperatorName() = Utils.app.getTelephonyManager().networkOperatorName


/**
 * 获取移动网络运营商名称
 */
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun networkGetType(): NetworkType {
    var netType = NetworkType.NETWORK_NO
    val info = getActiveNetworkInfo()
    if (info != null && info.isAvailable) {
        when (info.type) {
            ConnectivityManager.TYPE_WIFI -> netType = NetworkType.NETWORK_WIFI
            ConnectivityManager.TYPE_MOBILE -> netType = when (info.subtype) {
                NETWORK_TYPE_GSM, TelephonyManager.NETWORK_TYPE_GPRS, TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_EDGE, TelephonyManager.NETWORK_TYPE_1xRTT, TelephonyManager.NETWORK_TYPE_IDEN -> NetworkType.NETWORK_2G
                NETWORK_TYPE_TD_SCDMA, TelephonyManager.NETWORK_TYPE_EVDO_A, TelephonyManager.NETWORK_TYPE_UMTS, TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_HSDPA, TelephonyManager.NETWORK_TYPE_HSUPA, TelephonyManager.NETWORK_TYPE_HSPA, TelephonyManager.NETWORK_TYPE_EVDO_B, TelephonyManager.NETWORK_TYPE_EHRPD, TelephonyManager.NETWORK_TYPE_HSPAP -> NetworkType.NETWORK_3G
                NETWORK_TYPE_IWLAN, TelephonyManager.NETWORK_TYPE_LTE -> NetworkType.NETWORK_4G
                else -> {
                    val subtypeName = info.subtypeName
                    if (subtypeName.equals("TD-SCDMA", ignoreCase = true)
                        || subtypeName.equals("WCDMA", ignoreCase = true)
                        || subtypeName.equals("CDMA2000", ignoreCase = true)
                    ) NetworkType.NETWORK_3G
                    else NetworkType.NETWORK_UNKNOWN
                }
            }
            else -> netType = NetworkType.NETWORK_UNKNOWN
        }
    }
    return netType
}

@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
private fun getActiveNetworkInfo() = Utils.app.getConnectivityManager().activeNetworkInfo


/**
 * 获取 IP 地址
 *
 * @param useIPv4 是否适用IPV4地址
 */
@RequiresPermission(Manifest.permission.INTERNET)
fun networkGetIPAddress(useIPv4: Boolean): String {
    try {
        val nis = NetworkInterface.getNetworkInterfaces()
        while (nis.hasMoreElements()) {
            val ni = nis.nextElement()
            if (!ni.isUp) continue
            val addresses = ni.inetAddresses
            while (addresses.hasMoreElements()) {
                val inetAddress = addresses.nextElement()
                if (!inetAddress.isLoopbackAddress) {
                    val hostAddress = inetAddress.hostAddress
                    val isIPv4 = hostAddress.indexOf(':') < 0
                    if (useIPv4) if (isIPv4) return hostAddress
                    else {
                        if (!isIPv4) {
                            val index = hostAddress.indexOf('%')
                            return if (index < 0) hostAddress.toUpperCase(Locale.getDefault())
                            else hostAddress.substring(0, index).toUpperCase(Locale.getDefault())
                        }
                    }
                }
            }
        }
    } catch (e: SocketException) {
        e.printStackTrace()
    }
    return ""
}

/**
 * 获取域名 ip 地址
 *
 * @param domain 域名
 */
@RequiresPermission(Manifest.permission.INTERNET)
fun networkGetDomainAddress(domain: String) = try {
    InetAddress.getByName(domain).hostAddress
} catch (e: UnknownHostException) {
    ""
}
